﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Windows.Forms;

namespace Slippor.Common.PluginFramework
{
    public class PluginManager
    {
        private readonly IApplication _application;
        private readonly List<PluginInfo> _pluginInfos = new List<PluginInfo>();
        private readonly IPluginService _pluginService;
        public PluginManager(IApplication application)
        {
            _application = application;
            _pluginService = (IPluginService)_application.GetService(typeof(IPluginService));
            PluginPath = String.Empty;
        }

        public string PluginPath { get; set; }

        public List<PluginInfo> PluginInfos
        {
            get { return _pluginInfos; }
        }

        public void InitialPlugins()
        {
            var dir = new DirectoryInfo(PluginPath);
            if (!dir.Exists)
            {
                dir.Create();
            }
            FileInfo[] plugins = dir.GetFiles("*.dll", SearchOption.AllDirectories);
            _pluginInfos.Clear();
            foreach (FileInfo plugin in plugins)
            {
                FindPluginFromAssembly(plugin);
            }
            CheckExistedPlugin();
        }

        private void FindPluginFromAssembly(FileInfo file)
        {
            Assembly assembly = Assembly.LoadFile(file.FullName);
            try
            {
                Type[] types = assembly.GetTypes();
                foreach (Type type in types)
                {
                    if (!type.IsAbstract && type.GetInterface("IPlugin") != null)
                    {
                        PluginInfo pInfo = PluginInfo.GetPluginInfo(type);
                        pInfo.PluginFile = GetFileName(file);
                        _pluginInfos.Add(pInfo);
                    }
                }
            }
            catch (ReflectionTypeLoadException)
            {
                MessageBox.Show(String.Format("{0} 中包含与当前程序版本不符的插件程序，请更新主程序或插件。", file.FullName));
            }
        }

        private string GetFileName(FileInfo file)
        {
            var dir = new DirectoryInfo(PluginPath);
            String fileName = file.Name;
            var fileDir = file.Directory;
            while(fileDir.FullName != dir.FullName)
            {
                fileName = Path.Combine(fileDir.Name, fileName);
                fileDir = fileDir.Parent;
            }
            return fileName;
        }

        private void CheckExistedPlugin()
        {
            if (_pluginService != null)
            {
                var nameList = new List<string>();
                String[] pluginNames = _pluginService.GetAllPluginNames();
                nameList.AddRange(pluginNames);
                foreach (PluginInfo pInfo in _pluginInfos)
                {
                    if (nameList.Contains(pInfo.PluginName))
                    {
                        pInfo.IsEnabled = true;
                        if(pInfo.IsConfigable)
                        {
                            _pluginService.SetConfig(pInfo);
                        }
                    }
                }
            }
        }

        public void ReloadPlugin(PluginInfo pInfo)
        {
            _pluginService.ReloadPlugin(pInfo);
        }

        public void UpdatePlugin(PluginInfo pInfo)
        {
            var nameList = new List<string>();
            String[] pluginNames = _pluginService.GetAllPluginNames();
            nameList.AddRange(pluginNames); 
            if (pInfo.IsEnabled)
            {
                if (!nameList.Contains(pInfo.PluginName))
                {
                    _pluginService.AddPlugin(pInfo);
                    _pluginService.LoadPlugin(pInfo.PluginName);
                }
            }
            else
            {
                if (nameList.Contains(pInfo.PluginName))
                {
                    _pluginService.UnLoadPlugin(pInfo.PluginName);
                    _pluginService.RemovePlugin(pInfo.PluginName);
                }
            }
        }

        public void UpdatePlugins()
        {
            if (_pluginService != null)
            {
                var nameList = new List<string>();
                String[] pluginNames = _pluginService.GetAllPluginNames();
                nameList.AddRange(pluginNames); 
                foreach (PluginInfo pInfo in _pluginInfos)
                {
                    if (pInfo.IsEnabled)
                    {
                        if (nameList.Contains(pInfo.PluginName))
                        {
                            continue;
                        }
                        _pluginService.AddPlugin(pInfo);
                        _pluginService.LoadPlugin(pInfo.PluginName);
                    }
                    else
                    {
                        if (nameList.Contains(pInfo.PluginName))
                        {
                            _pluginService.UnLoadPlugin(pInfo.PluginName);
                            _pluginService.RemovePlugin(pInfo.PluginName);
                        }
                    }
                }
            }
        }

        public IPlugin GetPluginInstance(PluginInfo pInfo)
        {
            IPlugin plugin =  _pluginService.GetPluginInstance(pInfo.PluginName);
            return plugin;
        }
    }
}